using System;
using System.Linq;

namespace Snake.Gameplay
{
    public class GameplayTagContainer
    {
        private readonly GameplayTagContainerNode _tags = new GameplayTagContainerNode();

        public GameplayAbilityComponent Owner { get; }

        public GameplayTagContainer(GameplayAbilityComponent owner)
        {
            Owner = owner;
        }

        private GameplayTagContainerNode FindNode(string path)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new NotSupportedException("Path is invalid.");
            }

            var node = _tags;
            var keys = path.Split('.');
            foreach (var key in keys)
            {
                node = node.FindNode(key);
            }

            return node;
        }

        public void AddTag(params string[] tags)
        {
            foreach (var tag in tags)
            {
                FindNode(tag).Add();
            }

            foreach (var tag in tags)
            {
                Owner.BroadcastEvent(new GameplayAddTagEvent
                {
                    Tag = tag
                });
            }
        }

        public void RemoveTag(params string[] tags)
        {
            foreach (var tag in tags)
            {
                FindNode(tag).Remove();
            }

            foreach (var tag in tags)
            {
                Owner.BroadcastEvent(new GameplayRemoveTagEvent
                {
                    Tag = tag
                });
            }
        }

        /// <summary>
        /// 移除所有Tag
        /// </summary>
        /// <param name="tags"></param>
        public void RemoveAllTag(params string[] tags)
        {
            foreach (var tag in tags)
            {
                FindNode(tag).RemoveAll();
            }
        }

        public bool HasAll(params string[] tags)
        {
            return tags.Length != 0 && tags.All(HasTag);
        }

        public bool HasTag(string tag)
        {
            if (string.IsNullOrEmpty(tag))
            {
                return false;
            }

            return FindNode(tag).Count > 0;
        }

        public bool HasAny(params string[] tags)
        {
            return tags.Length != 0 && tags.Any(HasTag);
        }

        public int TagCount(string tag)
        {
            return FindNode(tag).Count;
        }
    }
}